package com.supreme.threadserver.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.supreme.commonboot.exception.BizException;
import com.supreme.commonentity.mysql.primary.*;
import com.supreme.commonmybatis.entity.primary.MBGoods;
import com.supreme.commonmybatis.service.quick.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class JucTransactionService {

    @Resource
    private BizUserOrmService bizUserOrmService;

    @Resource
    private ExtBizGoodsService extBizGoodsService;

    @Resource
    private ExtBatchRedService extBatchRedService;

    @Resource
    private ExtBatchGreenService extBatchGreenService;

    @Resource
    private ExtBatchBlueService extBatchBlueService;

    @Resource
    private AsyncThreadService asyncThreadService;

    @Resource
    private PlatformTransactionManager platformTransactionManager;

    @Resource
    private DataSourceTransactionManager dataSourceTransactionManager;

    @Resource
    private DefaultTransactionDefinition transactionDefinition;

    @Resource
    private JdbcTemplate jdbcTemplate;

    public Future<Boolean> insertBizUserList(List<BizUser> users) {
        boolean saveBatch = bizUserOrmService.saveBatch(users, users.size());
        return AsyncResult.forValue(saveBatch);
    }

    public void createOrderProcess(String userCode, String goodsCode, Integer stockNum) {
        Integer userId = Optional.ofNullable(bizUserOrmService.getOne(Wrappers.lambdaQuery(BizUser.class).eq(BizUser::getUserCode, userCode)))
                .map(BizUser::getUserId)
                .orElseThrow(() -> new BizException("User Not Found"));

        Long goodsId = Optional.ofNullable(extBizGoodsService.getOne(Wrappers.lambdaQuery(MBGoods.class).eq(MBGoods::getGoodsName, goodsCode)))
                .map(MBGoods::getGoodsId)
                .orElseThrow(() -> new BizException("Goods Not Found"));
    }

    public List<BatchBase> getBaseBatchList(String batchCode) {
        BatchRed batchRed = extBatchRedService.getOne(Wrappers.lambdaQuery(BatchRed.class).eq(BatchRed::getBatchCode, batchCode));
        BatchGreen batchGreen = extBatchGreenService.getOne(Wrappers.lambdaQuery(BatchGreen.class).eq(BatchGreen::getBatchCode, batchCode));
        BatchBlue batchBlue = extBatchBlueService.getOne(Wrappers.lambdaQuery(BatchBlue.class).eq(BatchBlue::getBatchCode, batchCode));
        return Stream.of(batchRed, batchGreen, batchBlue).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public JSONObject createAllRandomBatchList(String batchCode, int expValue) {
        String syncCode = RandomStringUtils.randomAlphabetic(16).toLowerCase();
        int syncVersion = RandomUtils.nextInt(1000, 9999);
        log.info("syncVersion = {}", syncVersion);

        BatchRed batchRed = new BatchRed()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchRedService.saveOrUpdate(batchRed, Wrappers.lambdaQuery(BatchRed.class).eq(BatchRed::getBatchCode, batchCode));

        BatchGreen batchGreen = new BatchGreen()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchGreenService.saveOrUpdate(batchGreen, Wrappers.lambdaQuery(BatchGreen.class).eq(BatchGreen::getBatchCode, batchCode));

        BatchBlue batchBlue = new BatchBlue()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchBlueService.saveOrUpdate(batchBlue, Wrappers.lambdaQuery(BatchBlue.class).eq(BatchBlue::getBatchCode, batchCode));

        if (expValue > 1) {
            /*if (syncVersion % expValue == 0) {
                throw new BizException(String.format("syncVersion不能是 %d 的倍数", expValue));
            }*/
            throw new BizException("expValue不能大于1");
        }

        return new JSONObject()
                .fluentPut("syncCode", syncCode)
                .fluentPut("syncVersion", syncVersion);
    }

    @Transactional(rollbackFor = Exception.class)
    public void createRandomBatchListSync(String batchCode, int expValue) {
        String syncCode = RandomStringUtils.randomAlphabetic(16).toLowerCase();
        int syncVersion = RandomUtils.nextInt(1000, 9999);
        log.info("syncVersion = {}", syncVersion);

        BatchRed batchRed = new BatchRed()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchRedService.saveOrUpdate(batchRed, Wrappers.lambdaQuery(BatchRed.class).eq(BatchRed::getBatchCode, batchCode));

        BatchGreen batchGreen = new BatchGreen()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchGreenService.saveOrUpdate(batchGreen, Wrappers.lambdaQuery(BatchGreen.class).eq(BatchGreen::getBatchCode, batchCode));

        asyncThreadService.createBatchBlueException(batchCode, syncCode, syncVersion, expValue);
    }

    @Transactional(rollbackFor = Exception.class)
    public void createRandomBatchListAsync1(String batchCode, int expValue) {
        String syncCode = RandomStringUtils.randomAlphabetic(16).toLowerCase();
        int syncVersion = RandomUtils.nextInt(1000, 9999);
        log.info("syncVersion = {}", syncVersion);

        BatchRed batchRed = new BatchRed()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchRedService.saveOrUpdate(batchRed, Wrappers.lambdaQuery(BatchRed.class).eq(BatchRed::getBatchCode, batchCode));

        BatchGreen batchGreen = new BatchGreen()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchGreenService.saveOrUpdate(batchGreen, Wrappers.lambdaQuery(BatchGreen.class).eq(BatchGreen::getBatchCode, batchCode));

        asyncThreadService.asyncCreateBatchBlue(batchCode, syncCode, syncVersion);

        if (expValue > 1) {
            if (syncVersion % expValue == 0) {
                throw new BizException(String.format("syncVersion不能是 %d 的倍数", expValue));
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void createRandomBatchListAsync2(String batchCode, int expValue) {
        String syncCode = RandomStringUtils.randomAlphabetic(16).toLowerCase();
        int syncVersion = RandomUtils.nextInt(1000, 9999);
        log.info("syncVersion = {}", syncVersion);

        BatchRed batchRed = new BatchRed()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchRedService.saveOrUpdate(batchRed, Wrappers.lambdaQuery(BatchRed.class).eq(BatchRed::getBatchCode, batchCode));

        asyncThreadService.asyncCreateBatchGreenException(batchCode, syncCode, syncVersion, expValue);

        BatchBlue batchBlue = new BatchBlue()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchBlueService.saveOrUpdate(batchBlue, Wrappers.lambdaQuery(BatchBlue.class).eq(BatchBlue::getBatchCode, batchCode));
    }

    @Transactional(rollbackFor = Exception.class)
    public void createRandomBatchListComplete1(String batchCode, int expValue) {
        String syncCode = RandomStringUtils.randomAlphabetic(16).toLowerCase();
        int syncVersion = RandomUtils.nextInt(1000, 9999);
        log.info("syncVersion = {}", syncVersion);

        BatchRed batchRed = new BatchRed()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchRedService.saveOrUpdate(batchRed, Wrappers.lambdaQuery(BatchRed.class).eq(BatchRed::getBatchCode, batchCode));

        BatchGreen batchGreen = new BatchGreen()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchGreenService.saveOrUpdate(batchGreen, Wrappers.lambdaQuery(BatchGreen.class).eq(BatchGreen::getBatchCode, batchCode));

        CompletableFuture.runAsync(() -> {
            BatchBlue batchBlue = new BatchBlue()
                    .setBatchCode(batchCode)
                    .setSyncCode(syncCode)
                    .setSyncVersion(syncVersion);
            extBatchBlueService.saveOrUpdate(batchBlue, Wrappers.lambdaQuery(BatchBlue.class).eq(BatchBlue::getBatchCode, batchCode));
        });

        if (expValue > 1) {
            if (syncVersion % expValue == 0) {
                throw new BizException(String.format("syncVersion不能是 %d 的倍数", expValue));
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void createRandomBatchListComplete2(String batchCode, int expValue) {
        String syncCode = RandomStringUtils.randomAlphabetic(16).toLowerCase();
        int syncVersion = RandomUtils.nextInt(1000, 9999);
        log.info("syncVersion = {}", syncVersion);

        BatchRed batchRed = new BatchRed()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchRedService.saveOrUpdate(batchRed, Wrappers.lambdaQuery(BatchRed.class).eq(BatchRed::getBatchCode, batchCode));

        BatchGreen batchGreen = new BatchGreen()
                .setBatchCode(batchCode)
                .setSyncCode(syncCode)
                .setSyncVersion(syncVersion);
        extBatchGreenService.saveOrUpdate(batchGreen, Wrappers.lambdaQuery(BatchGreen.class).eq(BatchGreen::getBatchCode, batchCode));

        CompletableFuture.runAsync(() -> {
            BatchBlue batchBlue = new BatchBlue()
                    .setBatchCode(batchCode)
                    .setSyncCode(syncCode)
                    .setSyncVersion(syncVersion);
            extBatchBlueService.saveOrUpdate(batchBlue, Wrappers.lambdaQuery(BatchBlue.class).eq(BatchBlue::getBatchCode, batchCode));

            if (expValue > 1) {
                if (syncVersion % expValue == 0) {
                    throw new BizException(String.format("syncVersion不能是 %d 的倍数", expValue));
                }
            }
        });
    }

    public int createRandomBatchListComplete3(String batchCode, int expValue) {
        String syncCode = RandomStringUtils.randomAlphabetic(16).toLowerCase();
        int syncVersion = RandomUtils.nextInt(1000, 9999);
        log.info("syncVersion = {}", syncVersion);

        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {

        });
        AtomicBoolean atomicStatus = new AtomicBoolean(false);

        CompletableFuture<BatchRed> batchRedCompletableFuture = CompletableFuture.supplyAsync(new Supplier<BatchRed>() {
            @Override
            public BatchRed get() {
                TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);

                BatchRed batchRed = new BatchRed()
                        .setBatchCode(batchCode)
                        .setSyncCode(syncCode)
                        .setSyncVersion(syncVersion);
                extBatchRedService.saveOrUpdate(batchRed, Wrappers.lambdaQuery(BatchRed.class).eq(BatchRed::getBatchCode, batchCode));

                if (atomicStatus.get()) {
                    dataSourceTransactionManager.rollback(transactionStatus);
                } else {
                    dataSourceTransactionManager.commit(transactionStatus);
                }

                return batchRed;
            }
        });

        CompletableFuture<BatchGreen> batchGreenCompletableFuture = CompletableFuture.supplyAsync(new Supplier<BatchGreen>() {
            @Override
            public BatchGreen get() {
                TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);

                BatchGreen batchGreen = new BatchGreen()
                        .setBatchCode(batchCode)
                        .setSyncCode(syncCode)
                        .setSyncVersion(syncVersion);
                extBatchGreenService.saveOrUpdate(batchGreen, Wrappers.lambdaQuery(BatchGreen.class).eq(BatchGreen::getBatchCode, batchCode));

                if (atomicStatus.get()) {
                    dataSourceTransactionManager.rollback(transactionStatus);
                } else {
                    dataSourceTransactionManager.commit(transactionStatus);
                }

                return batchGreen;
            }
        });

        CompletableFuture<BatchBlue> batchBlueCompletableFuture = CompletableFuture.supplyAsync(new Supplier<BatchBlue>() {
            @Override
            public BatchBlue get() {
                TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);

                BatchBlue batchBlue = new BatchBlue()
                        .setBatchCode(batchCode)
                        .setSyncCode(syncCode)
                        .setSyncVersion(syncVersion);
                extBatchBlueService.saveOrUpdate(batchBlue, Wrappers.lambdaQuery(BatchBlue.class).eq(BatchBlue::getBatchCode, batchCode));

                if (expValue > 1) {
                    atomicStatus.set(true);
//                    throw new BizException(String.format("expValue是 %d", expValue));
                }

                if (atomicStatus.get()) {
                    dataSourceTransactionManager.rollback(transactionStatus);
                } else {
                    dataSourceTransactionManager.commit(transactionStatus);
                }

                return batchBlue;
            }
        });

        CompletableFuture.allOf(batchRedCompletableFuture, batchGreenCompletableFuture, batchBlueCompletableFuture)
                .whenComplete((unused, throwable) -> {
                    Optional.ofNullable(throwable).map(Throwable::getMessage).ifPresent(System.out::println);
                    System.out.println("allOf whenComplete");
                });

        return syncVersion;
    }
}
